package jass.contact;
import jass.engine.*;

/**
   A force model based on stick slip model.
   Karnopp model.
   
   Model is in terms of q(t):

   Md^2q/dt^2 + k_d dq/dt + k_s q(t) = G(dq/dt)  FOR |v-dq/dt| > vc
   @author Kees van den Doel (kvdoel@cs.ubc.ca)
*/
public class KarnoppFriction extends Out {

    private float srate; // sampling rate in Hertz
    private float k_damp; // damping of model
    private float k_spring; // spring constant of model
    private float mu_static; // static (Stribeck) friction coeff.
    private float mu_dynamic; // dynamic  friction coeff.
    private float v_crit; // critical velocity of model
    private float mass; // masss of effective model
    
    private double qt_1,rt_1; // last state
    private float v=1; // external slide velocity in m/s
    private float fn=1; // external normal force in Newton
    
    /** Construct force.
        @param srate sampling rate in Hertz.
        @param bufferSize bufferSize of this Out.
    */
    public KarnoppFriction(float srate, int bufferSize) {
        super(bufferSize);
        this.srate = srate;
        reset();
    }

    /** Set stick-slip model parameters (all in S.I. units).
        @param k_damp damping of spring system
        @param mu_static static friction coeff
        @param mu_dynamic dynamic friction coeff
        @param v_crit critical velocity for transition from dyn. to static friction
    */
    public void setStickSlipParameters(float mass,float k_damp,float k_spring,float mu_static,float mu_dynamic,float v_crit) {
        this.k_damp = k_damp;
        this.k_spring = k_spring;
        this.mu_static = mu_static;
        this.mu_dynamic = mu_dynamic;
        this.v_crit = v_crit;
        this.mass = mass;
    }

    /** Set normal force magnitude.
        @param val normal force in Newton
    */
    public void setNormalForce(float val) {
        fn = val;
    }

    /** Set velocity.
        @param v velocity in m/s
    */
    public void setSpeed(float v) {
        this.v = v;
    }

    /** Reset state.
     */
    public void reset() {
        qt_1 = rt_1 = 0;
    }
    
    /**
       G2(r) = Fn*sign(v-r) *[ mu_dyn + mu_stat (if|(v-r)|>vc]
    */
    private double G2(double r) {
        double x = v - r;
        int signOf = (x > 0 ? 1 : -1);
        double absx = Math.abs(x);
        double ret = signOf*fn*(mu_dynamic + mu_static * (absx>v_crit?0:1));
        return ret;
    }
    
    /** Compute the next buffer.
        Discrete model with r = dq/dt:
        r(t+1) = (1-k_d/(srate*M))r(t) - k_s/(srate*M) * q(t)+G(r(t))/(M*srate)
        q(t+1) = q(t)+r(t)/srate
    */
    public void computeBuffer() {
        double foos = k_spring/(mass * srate);
        double food = 1. - k_damp/(mass * srate);
        double bard = fn*mu_dynamic/(mass * srate);
        double bars = fn*mu_static/(mass * srate);
        int bufsz = getBufferSize();        
        for(int k=0;k<bufsz;k++) {
            double vdiff = v - rt_1;
            double absvdiff,rnew,qnew;
            int signOf;
            if(vdiff>0) {
                absvdiff = vdiff;
                signOf = 1;
            } else {
                absvdiff = -vdiff;
                signOf = -1;
            }
            if(absvdiff > v_crit) { // slip
                rnew = food * rt_1 - foos*qt_1 + bard*signOf;
                qnew = qt_1 + rt_1/srate;
            } else { // sticking 
                double breakAwayForce = fn * mu_static;
                double appliedForce = Math.abs(k_spring*qt_1+k_damp*rt_1);
                if(appliedForce > breakAwayForce) { // slipping in static friction region
                    rnew = food * rt_1 - foos*qt_1 + bars*signOf;
                    qnew = qt_1 + rt_1/srate;
                } else { // stick
                    rnew = v;
                    //rnew = rt_1; // zero force
                    qnew = qt_1 + rt_1/srate;
                }
            }
            buf[k] = (float)(rt_1+rnew);
            qt_1 = qnew;
            rt_1 = rnew;
            //System.out.println("q="+qnew);
        }
    }

}




